﻿using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Common.DataAnnotations;
using System.Collections;
using Newtonsoft.Json;

namespace Common.Web
{
    /// <summary>
    /// 敏感数据映射
    /// </summary>
    public class SensitiveDataBinderProvider : IModelBinderProvider
    {
        /// <summary>
        /// 获取模型绑定器
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            DefaultModelMetadata modelMetadata = context.Metadata as DefaultModelMetadata;
            if (modelMetadata == null)
            {
                return null;
            }
            var attr = modelMetadata.Attributes.Attributes.OfType<SensitiveDataAttribute>().Any();
            if (attr)
            {
                return new SensitiveDataBinder();
            }
            return null;
        }
    }

    /// <summary>
    /// 敏感数据映射（HttpGet）
    /// </summary>
    public class SensitiveDataBinder : IModelBinder
    {
        /// <summary>
        /// 绑定模型
        /// </summary>
        /// <param name="bindingContext"></param>
        /// <returns></returns>
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (value.Count() <= 0)
            {
                return Task.CompletedTask;
            }
            Type modelType = bindingContext.ModelType;
            if (modelType.IsArray || (modelType.IsGenericType && modelType.GetInterface(typeof(IEnumerable).Name) != null))
            {
                var eleType = modelType.IsGenericType ? modelType.GetGenericArguments().First() : modelType.GetElementType();
                string val = value.FirstValue;
                string[] ciphers = val.Split(',');
                object[] plains = new object[ciphers.Length];
                for (int i = 0; i < ciphers.Length; i++)
                {
                    var decodeV = SensitiveDataController.Provider.Decode(ciphers[i]);
                    object v = Convert.ChangeType(decodeV, eleType);
                    plains.SetValue(v, i);
                }
                bindingContext.Result = ModelBindingResult.Success(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(plains), modelType));
                return Task.CompletedTask;
            }
            else
            {
                var deValue = SensitiveDataController.Provider.Decode(value.FirstValue);
                if (string.IsNullOrEmpty(deValue + string.Empty))
                {
                    return Task.CompletedTask;
                }
                var type = bindingContext.ModelType;
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    type = Nullable.GetUnderlyingType(type);
                }
                var valueResult = Convert.ChangeType(deValue, type);

                bindingContext.Result = ModelBindingResult.Success(valueResult);
                return Task.CompletedTask;
            }
        }
    }
}
